﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using NhWeather.IO;
using NhWeather.Modbus;
using NhWeather.Register;
using NhWeather.Service;

namespace NhWeather.nModbusDevice;

/// <summary>
/// 数据记录仪
/// </summary>
public class DataRecorder : INotifyPropertyChanged
{
    /// <summary>
    /// 接受的命令集合
    /// </summary>
    private readonly HashSet<AcceptCmd> HasAcceptFrames;
    public ObservableCollection<BaseRegister> Registers = [];
    public WeatherData WtData;

    private readonly short[,] 值范围 = {
        { -400, 420 }, { 0, 1000 }, { 650, 11000 }, { 0, 400 }, { 0, 359 }, { 0, 100 }, { -400, 500 }, { 0, 1000 }
    };

    private bool _isRecorder;
    private int _maxHistoryData = 100;
    private byte _deviceAddress = 8;
    private string _deviceAddressHex = "08";
    private string _deviceType = "模拟传感器";

    public bool IsRecorder
    { 
        get => _isRecorder; 
        set => UpdateProperty(ref _isRecorder, value, () =>
        {
            DeviceType = value ? "模拟记录仪" : "模拟传感器";
        });
    }

    public int MaxHistoryData
    {
        get => _maxHistoryData; 
        set => UpdateProperty(ref _maxHistoryData, value, () =>
        {
            ReadHistoryCmd.MaxHistoryData = value;
        });        
    }

    /// <summary>
    /// 设备地址
    /// </summary>
    public byte DeviceAddress
    {
        get => _deviceAddress;
        set => UpdateProperty(ref _deviceAddress, value, () =>
        {
            DeviceAddressHex = value.ToString("X2");
        });
    }

    /// <summary>
    /// 16进制设备地址
    /// </summary>
    public string DeviceAddressHex
    {
        get => _deviceAddressHex;
        set
        {
            try
            {
                DeviceAddress = Convert.ToByte(value, 16);
                UpdateProperty(ref _deviceAddressHex, value);
            }
            catch { }
        }
    }

    public string DeviceType
    {
        get => _deviceType; 
        set => UpdateProperty(ref _deviceType, value);
    }

    public DataRecorder(byte address = 8)
    {
        DeviceAddress = address;
        WtData = new(Registers);

        HasAcceptFrames =
        [
            new ReadRegCmd(),
            new ReadHoldRegCmd(),
            new ReadHistoryCmd(),
            new WriteReg(),
            new WriteMultReg()
        ];
    }

    public void InitializeRegisters(bool isJly = true)
    {
        IsRecorder = isJly;
        Registers.Clear();
        ushort i = 0;
        for (; i < 3; i++)
        {
            BaseRegister cgq;
            if (IsRecorder)
            {
                cgq = new TimeRegister()
                {
                    RegAddress = i
                };
            }
            else
            {
                cgq = new SensorRegister(2000, 0)
                {
                    RegAddress = i
                };
            }
            Registers.Add(cgq);
        }

        for (; i < 3 + 8; i++)
        {
            SensorRegister cgq = new(值范围[i - 3, 1], 值范围[i - 3, 0])
            {
                RegAddress = i
            };
            Registers.Add(cgq);
        }

        for (; i < 3 + 24; i++)
        {
            SensorRegister cgq = new(2000, 0)
            {
                RegAddress = i
            };
            Registers.Add(cgq);
        }
    }

    public void UpdataTimeRegisters(bool isJly = true)
    {
        for (ushort i = 0; i < 3; i++)
        {
            BaseRegister cgq;
            if (isJly)
            {
                cgq = new TimeRegister()
                {
                    RegAddress = i
                };
            }
            else
            {
                cgq = new SensorRegister(2000, 0)
                {
                    RegAddress = i
                };
            }

            if (i < Registers.Count)
            {
                Registers[i] = cgq;
            }
            else
            {
                Registers.Add(cgq);
            }
        }
    }

    public byte[] RevcieveData(byte[] byts)
    {
        FrameValid frame = new(byts);

        if (!frame.IsValid) { return null; } //非法帧

        //if ((frame.Address == 0) && (DicRegisters.Count > 1)) { return; } //广播冲突

        if ((frame.Address == 0) || frame.Address == DeviceAddress)
        {
            var cmd = HasAcceptFrames.FirstOrDefault(c => c.Code == frame.Code);
            if (cmd != null)
            {
                WtData.Generate();
                return cmd.GetFrame(frame.Data, Registers, DeviceAddress);
            }
        }

        return null;
    }

    #region 属性通知
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }


    /// <summary>
    /// 更新属性并触发属性更改通知
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="properValue"></param>
    /// <param name="newValue"></param>
    /// <param name="onChanged">如要更改属性要运行的方法</param>
    /// <param name="propertyName"></param>
    protected void UpdateProperty<T>(ref T properValue, T newValue, Action onChanged = null, [CallerMemberName] string propertyName = null)
    {
        if (Equals(properValue, newValue))
        {
            return;
        }
        properValue = newValue;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
    }
    #endregion
}
